import 'package:decimal/decimal.dart';
import 'package:flutter/widgets.dart';
import 'package:intl/intl.dart';
import 'package:lib_core/lib_core.dart';

/// @Title  数字格式化相关方法
/// @Author: bryce
/// @CreateDate: 2024年04月17日16:59:35
class GTNumberFormatV3 {
  /// 将数字转换为千分位/百万分位/十亿分位,保留指定小数位
  /// 例如：1234567890.12345  -> 1,234,567,890.12
  /// scaleType:小数位保留方式：四舍五入、截断、向上向下取整
  /// endZeroType：保留小数后末尾为0的处理方式：裁掉末尾的0 (例如3.199四舍五入保留两位小数之后为3.20，则显示为3.2)
  ///                  :保留末尾的0 (例如3.1 保留两位小数之后显示为3.10)
  static String formatNumberThousands(
    String? num, {
    // 错误占位，当num为空时或者转换出错时的占位
    String placeholder = '--',
    // 保留小数位
    int scale = 2,
    // 保留小数位的方式：四舍五入、截断、向上向下取整
    GTNumberScaleType scaleType = GTNumberScaleType.truncate,
    // 末尾的0的状态，默认为裁掉末尾的0 (例如3.199四舍五入保留两位小数之后为3.20，则显示为3.2)
    GTNumberEndZeroType endZeroType = GTNumberEndZeroType.cutZero,
    // 是否在前面追加加号-当数字为正数时
    bool addPlusWhenPositive = false,
    // 绝对值最小的值，如果值小于此最小值.则使用0，例如（需求要求小于0.01的数字展示为0）
    double absMinValueToZero = 0,
  }) {
    NumberFormat format = NumberFormat("#,###,###,###,###,##0", Intl.systemLocale);
    // format.maximumFractionDigits = scale;
    // if (endZeroType == GTNumberEndZeroType.appendZero) {
    //   // 确保小数点后最少也有 scale 位数字，不足的补零
    //   format.minimumFractionDigits = scale;
    // }
    return formatDecimalToStr(num,
        placeholder: placeholder,
        scale: scale,
        scaleType: scaleType,
        endZeroType: endZeroType,
        addPlusWhenPositive: addPlusWhenPositive,
        absMinValueToZero: absMinValueToZero,
        numberFormat: format);
  }

  /// 将数字转换为K或M，保留指定小数位
  /// 例如：1,500 = 1.5k，1,500,000 = 1.5m
  static String formatNumberStrKM(
    String? num, {
    // 错误占位，当num为空时或者转换出错时的占位
    String placeholder = '--',
    // 保留小数位
    int scale = 2,
    // 保留小数位的方式：四舍五入、截断、向上向下取整
    GTNumberScaleType scaleType = GTNumberScaleType.truncate,
    // 末尾的0的状态，默认为裁掉末尾的0 (例如3.199四舍五入保留两位小数之后为3.20，则显示为3.2)
    GTNumberEndZeroType endZeroType = GTNumberEndZeroType.cutZero,
    // 是否在前面追加加号-当数字为正数时
    bool addPlusWhenPositive = false,
    // 绝对值最小的值，如果值小于此最小值.则使用0，例如（需求要求小于0.01的数字展示为0）
    double absMinValueToZero = 0,
  }) {
    if (null == num) return placeholder;
    Decimal? decimal = Decimal.tryParse(num);
    if (null == decimal) return placeholder;
    final language = GTLibCore.globalConfig.language;
    final isChina = language == 'cn' || language == 'tw';
    String result = '';
    // 结尾的单位
    String endUnit = '';
    if (isChina) {
      if (decimal.abs() >= Decimal.fromInt(100000000)) {
        result = (decimal / Decimal.parse('100000000')).toDecimal().toString();
        endUnit = '亿';
      } else if (decimal.abs() >= Decimal.fromInt(10000)) {
        result = (decimal / Decimal.parse('10000')).toDecimal().toString();
        endUnit = '万';
      } else {
        result = decimal.toString();
        endUnit = '';
      }
    } else {
      if (decimal.abs() >= Decimal.fromInt(1000000)) {
        result = (decimal / Decimal.parse('1000000')).toDecimal().toString();
        endUnit = 'M';
      } else if (decimal.abs() >= Decimal.fromInt(1000)) {
        result = (decimal / Decimal.parse('1000')).toDecimal().toString();
        endUnit = 'K';
      } else {
        result = decimal.toString();
        endUnit = '';
      }
    }
    return '${formatDecimalToStr(
      result,
      placeholder: placeholder,
      scale: scale,
      scaleType: scaleType,
      endZeroType: endZeroType,
      addPlusWhenPositive: addPlusWhenPositive,
      absMinValueToZero: absMinValueToZero,
    )}$endUnit';
  }

  /// 将小数转换为百分比
  /// maxFractionDigits:保留的最大小数位（即如果后面是0可以去掉）
  /// 例如：0.031415 -> 3.14%
  /// 0.031495 -> 3.15%
  /// 0.031000 -> 3.1%
  /// 参数含义同 formatNumberThousands
  static String formatNumToPercentage(
    String num, {
    // 错误占位，当num为空时或者转换出错时的占位
    String placeholder = '--',
    // 保留小数位
    int scale = 2,
    // 保留小数位的方式：四舍五入、截断、向上向下取整
    GTNumberScaleType scaleType = GTNumberScaleType.truncate,
    // 末尾的0的状态，默认为裁掉末尾的0 (例如3.199四舍五入保留两位小数之后为3.20，则显示为3.2)
    GTNumberEndZeroType endZeroType = GTNumberEndZeroType.cutZero,
    // 是否在前面追加加号-当数字为正数时
    bool addPlusWhenPositive = false,
    // 绝对值最小的值，如果值小于此最小值.则使用0，例如（需求要求小于0.01的数字展示为0）
    double absMinValueToZero = 0,
  }) {
    if (num.isEmpty) return placeholder;
    Decimal? decimal = Decimal.tryParse(num);
    if (null == decimal) return placeholder;
    return '${formatNumberThousands(
      '${decimal * Decimal.parse('100')}',
      placeholder: placeholder,
      scale: scale,
      scaleType: scaleType,
      endZeroType: endZeroType,
      addPlusWhenPositive: addPlusWhenPositive,
      absMinValueToZero: absMinValueToZero * 100,
    )}%';
  }

  /// 保留小数位
  /// scale：保留小数位
  /// scaleType：保留小数位的方式，四舍五入、截断、向上向下取整
  static Decimal formatDecimal(
    String num,
    int scale, {
    GTNumberScaleType scaleType = GTNumberScaleType.truncate,
  }) =>
      formatDecimalFromDecimal(Decimal.tryParse(num) ?? Decimal.zero, scale, scaleType: scaleType);

  /// 保留小数位
  static String formatDecimalToStr(
    String? num, {
    // 错误占位，当num为空时或者转换出错时的占位
    String placeholder = '--',
    // 保留小数位
    int scale = 2,
    // 保留小数位的方式：四舍五入、截断、向上向下取整
    GTNumberScaleType scaleType = GTNumberScaleType.truncate,
    // 末尾的0的状态，默认为裁掉末尾的0 (例如3.199四舍五入保留两位小数之后为3.20，则显示为3.2)
    GTNumberEndZeroType endZeroType = GTNumberEndZeroType.cutZero,
    // 是否在前面追加加号-当数字为正数时
    bool addPlusWhenPositive = false,
    // 绝对值最小的值，如果值小于此最小值.则使用0，例如（需求要求小于0.01的数字展示为0）
    double absMinValueToZero = 0,
    // 格式化整数位
    NumberFormat? numberFormat,
  }) {
    if (null == num) return placeholder;
    Decimal? decimal = Decimal.tryParse(num);
    if (null == decimal) return placeholder;
    if (decimal.toDouble().abs() < absMinValueToZero) {
      decimal = Decimal.zero;
    }

    String intPart;
    String needFormatIntPart = num.contains('.') ? num.split('.').first : num;
    if (null != numberFormat) {
      // 这里如果整数部分是0的话，如果前面是负号，会舍弃负号,所有要判断源数据为负数时加上负号
      intPart = numberFormat.format((Decimal.tryParse(needFormatIntPart) ?? Decimal.zero).toDouble());
      if (!intPart.startsWith('-') && decimal < Decimal.zero) {
        intPart = '-$intPart';
      }
    } else {
      intPart = needFormatIntPart;
    }

    Decimal scaledDecimal = formatDecimalFromDecimal(decimal, scale, scaleType: scaleType);
    String result;
    switch (endZeroType) {
      // 直接截取
      case GTNumberEndZeroType.cutZero:
        String cutZeroResult = scaledDecimal.toString();
        if (cutZeroResult.contains('.')) {
          result = '$intPart.${cutZeroResult.split('.')[1]}';
        } else {
          result = intPart;
        }
        break;
      // 小数位数不够的补0
      case GTNumberEndZeroType.appendZero:
        if (scale == 0) {
          result = intPart;
        } else {
          BigInt intPartBigInt = scaledDecimal.toBigInt().abs();
          Decimal decimalPartAdd1 = (Decimal.one + scaledDecimal.abs() - intPartBigInt.toDecimal()).shift(scale);
          result = '$intPart.${decimalPartAdd1.toString().substring(1)}';
        }
    }

    if (decimal < Decimal.zero) {
      // 判断原始数字的值是负数；
      // Decimal decimalResult = Decimal.tryParse(result) ?? Decimal.zero;
      // 先判断结果值是否是负数，如果不是，则添加负号
      if (scaledDecimal > Decimal.zero) {
        result = '-$result';
      } else if (scaledDecimal == Decimal.zero) {
        // 如果省略小数后结果变成了0，判断前面是否有负号，有则去掉
        if (result.contains('-')) {
          result = result.substring(1);
        }
      } else {
        // 如果原始数字是负数，结果是也是负数，不需要添加负号
      }
    } else {}

    // 是否在数字前面加上'+'号；
    bool isAddPlusSign =
        (decimal.toDouble() >= 0 || decimal.toDouble().abs() < absMinValueToZero) && addPlusWhenPositive;
    return '${isAddPlusSign ? '+' : ''}$result';
  }

  /// 保留小数位
  /// scale：保留小数位
  /// scaleType：保留小数位的方式，四舍五入、截断、向上向下取整
  static Decimal formatDecimalFromDecimal(
    Decimal decimal,
    int scale, {
    GTNumberScaleType scaleType = GTNumberScaleType.truncate,
  }) {
    switch (scaleType) {
      case GTNumberScaleType.round:
        return decimal.round(scale: scale);
      case GTNumberScaleType.truncate:
        return decimal.truncate(scale: scale);
      case GTNumberScaleType.ceil:
        return decimal.ceil(scale: scale);
      case GTNumberScaleType.floor:
        return decimal.floor(scale: scale);
    }
  }

  /// 获取小数位数量
  static int getDecimalCount(double number) {
    Decimal decimal = Decimal.parse(number.toString());
    return decimal.scale;
  }

  /// 获取两位数相加,返回Decimal（防止丢失精度）
  static Decimal getNumAdd(String num1, String num2) {
    Decimal num1Decimal = Decimal.tryParse(num1) ?? Decimal.zero;
    Decimal num2Decimal = Decimal.tryParse(num2) ?? Decimal.zero;
    return (num1Decimal + num2Decimal).ceil();
  }

  /// 获取两位数相减,返回Decimal（防止丢失精度）
  static Decimal getNumSubtract(String num1, String num2) {
    Decimal num1Decimal = Decimal.tryParse(num1) ?? Decimal.zero;
    Decimal num2Decimal = Decimal.tryParse(num2) ?? Decimal.zero;
    return (num1Decimal - num2Decimal);
  }

  /// 获取两位数相乘,返回Decimal（防止丢失精度）
  static Decimal getNumMultiply(String num1, String num2) {
    Decimal num1Decimal = Decimal.tryParse(num1) ?? Decimal.zero;
    Decimal num2Decimal = Decimal.tryParse(num2) ?? Decimal.zero;
    return (num1Decimal * num2Decimal);
  }

  /// 获取两位数相除,返回Decimal（防止丢失精度）
  static Decimal getNumDivision(
    String num1,
    String num2, {
    // 相除保留的小数位数，如果不传则全显示小数
    int? scale,
    // 保留小数的方式
    GTNumberScaleType scaleType = GTNumberScaleType.truncate,
    // 如果scale为空时，并且相除得到的小数除不尽时，默认保留的小数位
    int rationalScale = 2,
  }) {
    Decimal num1Decimal = Decimal.tryParse(num1) ?? Decimal.zero;
    Decimal num2Decimal = Decimal.tryParse(num2) ?? Decimal.zero;
    if (num2Decimal == Decimal.zero) return num1Decimal;
    try {
      switch (scaleType) {
        case GTNumberScaleType.round:
          return (num1Decimal / num2Decimal)
              .toDecimal(scaleOnInfinitePrecision: scale, toBigInt: (value) => value.round());
        case GTNumberScaleType.truncate:
          return (num1Decimal / num2Decimal)
              .toDecimal(scaleOnInfinitePrecision: scale, toBigInt: (value) => value.truncate());
        case GTNumberScaleType.ceil:
          return (num1Decimal / num2Decimal)
              .toDecimal(scaleOnInfinitePrecision: scale, toBigInt: (value) => value.ceil());
        case GTNumberScaleType.floor:
          return (num1Decimal / num2Decimal)
              .toDecimal(scaleOnInfinitePrecision: scale, toBigInt: (value) => value.floor());
      }
    } catch (e) {
      switch (scaleType) {
        case GTNumberScaleType.round:
          return (num1Decimal / num2Decimal)
              .toDecimal(scaleOnInfinitePrecision: scale ?? rationalScale, toBigInt: (value) => value.round());
        case GTNumberScaleType.truncate:
          return (num1Decimal / num2Decimal)
              .toDecimal(scaleOnInfinitePrecision: scale ?? rationalScale, toBigInt: (value) => value.truncate());
        case GTNumberScaleType.ceil:
          return (num1Decimal / num2Decimal)
              .toDecimal(scaleOnInfinitePrecision: scale ?? rationalScale, toBigInt: (value) => value.ceil());
        case GTNumberScaleType.floor:
          return (num1Decimal / num2Decimal)
              .toDecimal(scaleOnInfinitePrecision: scale ?? rationalScale, toBigInt: (value) => value.floor());
      }
    }
  }
}

/// 数字保留小数位的类型
enum GTNumberScaleType {
  // 四舍五入
  round,
  // 截断
  truncate,
  // 向上取
  ceil,
  // 向下取
  floor
}

/// 数字保留小数位后末尾的0的处理类型
enum GTNumberEndZeroType {
  /// 去除末尾的0，(例如3.199四舍五入保留两位小数之后为3.20，则显示为3.2)
  cutZero,

  /// 位数不够补0，(例如3.1保留两位小数，则补充一个0显示为：3.10)
  appendZero,
}
